التعبيرات المنتظمة


احدى أكثر الميزات في البيرل اذ لم تكن من افضل الميزات وهي الوسائل الكثيره لمعالجه النصوص وعلى راسها RE تسمى ايضاًُ بالـ regex أو regexp ، تعرف التعبيرات المنتظمة بأنها صيغة للبحث عن النمط (patterns) ليجاد واستخراج التطابق في النصوص ، حيث ان النمط عبارة عن مجموعة من الاحرف المراد البحث عنها في النصوص او في سطر النصوص ومع لغة البيرل فهو الاحرف المتضمنة مع slash /...../ فمثلاً


/def/

الكلمة def تمثل النمط ، في حال كان لدينا النصوص "redefine" فأن النمط في هذه الحالة يطابق الحرف الثالث d والحرف الرابع e والحرف الخامس f .

مؤثرات المطابقة

هناك مؤثرين للمطابقة وهما

=~ يسترجع في التعبير قيمة الصواب true اذا النص فعلاً مطابق وغير ذلك فهو يعيد false
!~ فهو عكس السابق اي بتحدد الغير مطابق فقط.

#!usr/bin/perl
$input_text = "two pints of milk and a pot of yoghurt";
if ($input_text=~/milk/) {
print "found";
}
else  {
print "not found";
}

من الملاحظ انها حالة حساسة جداً في عملية المطابقة لذا لو ان الاحرف كانت Milk فسوف يسترجع القيمة false

من الممكن استخدام عملية المطابقة مع المتغير الخاص $_ والغالب يستخدم بكثره في البيرل

#!usr/bin/perl
$_ = "two pints of milk and a pot of yoghurt";
if (/milk/) {
print "found";
}
else  {
print "not found";
}

مثال اخر لادخال النص المطابق للمستخدم وذلك لإجراء تجربة النمط المطابقة سوف تستخدم لاحقاً مع مختلف الانماط اسفل

#!usr/bin/perl -w
$input = <>;
$p = 'pass';
print "Yes, got a match \n" if $input =~ /$p/;


الأحرف الخاصة مع النمط

توفر البيرل حروف خاصة داخل النمط التي تمكنك لمطابق اي رقم واي حرف وهنا بعض الحالات :


الحرف الوصف
. (اي حرف يطابق ماعدا السطر الجديد (حرف فقط
^ في بداية السطر او النصوص
$ في نهاية السطر او النصوص
* لاشئ او اكثر من الحرف الاخير
+ واحد او اكثر من الحرف الاخير
? لاشئ او واحد من الحرف الاخير


يجب ان توضع هذة الاحرف الخاصة داخل النمط /.../ والتالي بعض الامثلة :

/t.e/ يمكن ان تكون the او tre او tle .. الى غير ذلك ولكن لايطابق te او tale
/^f/ هل f في بداية السطر
/^ftp/ في بداية السطر ftp
/e$/ في نهاية السطر e
/tle$/ في نهاية السطر tle
/^def$/ مطابقة فقط def
/un*d/ يطابق لاشئ او اكثر من الحرف الاخير n ، ويمكن ان يطابق ud او und او unnd... الخ
/un+d/ يطابق واحد اواكثر في اخر حرف n ويمكن ان يطابق und او unnd او unnnd .... الخ ولايمكن ان يطابق ud
/un?d/ يطابق لاشئ او واحد من الحرف الاخير n ويمكن ان يطابق ud او und او uud ولايمكن ان يطابق unnd ا
/r+/ الابتداء بالحرف r ثم يلية اي عدد من المررات من r يمكن ان يطابق r, rr, rrr, rrrr, … وهذا يكافى النمط r+ = rr*
/.*/ اي نص ( غير السطر الجديد ) ، وهذا بسبب . يتوقع اي شئ ماعدا السطر الجديد و * يعني لاشئ او اكثر من حرف
/^$/ السطر الذي لاشئ فيه


الاقواس []:

تستعمل لاكثر من خيار ومطابقة اي حرف في هذا النطاق:

الرمز - يشير الى "بين"

الرمز ^ على البداية يعني "ليس"

امثله :
[0123456789] اما 0 او 1 او 2 ...... 9
[0-9] نفس السابق .
[qjk] اما q او j او k
[^qjk] ليس q ولا j ولا k
[a-z] اي حرف من a الى z (حروف صغيرة)
[^a-z] ليس من الحروف الصغيرة
[a-zA-Z] اي حرف من الحروف
[a-z]+ اي مجموعة احرف صغيرة مع الضرورة وجود حرف على الاقل .


علامات الحصر (.......) يمكن ان تستعمل لتجميع الاشياء معاً ، والرمز | فهو يمثل " او "

امثلة :
jelly|cream اما jelly او cream
(eg|le)gs اما eggs او legs
(da)+ اما da او dada او dadada .......


وهنا بعض من الرموز الخاصة

السلسة الوصف المماثل
\w اي حرف او رقم او underscores [a-zA-Z0-9_]
\W عكس السابق [^a-zA-Z0-9_]
\d اي رقم [0-9]
\D عكس السابق [^0-9]
\s whitespaceكالمسافة او السطر الجديد .... الخ [ \r\t\n\f]
\S whitespace بدون حرف [^ \r\t\n\f]
\b المطابق على حد الكلمة word boundary ، (لايوضع في الاقواس [] )
\B عكس السابق
\A المطابق في بداية السطر ^
\Z المطابق في نهاية السطر $


امثلة:
/\bdef/ المطابقة فقط اذا كانت def في بداية الكلمة ، هذا يعني انها تطابق def و defghi لكن ليس abcdef .
/def\b/ المطابقة اذا كانت def في نهاية الكلمة ، تطابق def وabcdef وليس defghi
/\bdef\b/ يطابق فقط def ، وليس abcdef و defghi .
/\bis\b/ يطابق فقط is ، مثلاً يطابق النص " A tulip is a flower " لكن لايطابق مع "A worm isn't"
/\Bdef/ عكس السابق ، يطابق abcdef ، ولايطابق def و defghi .
/\Bdef\B/ يطابق cdefg و abcdefghi ، وليس def و defghi و abcdef .

سلسة \b , \B بدون توقف كما هي دالة split التي سيتم ذكرها لاحقاً في هذا الجزء ان شاء الله :

#!/usr/bin/perl 
$thecount = 0;
print ("Enter the input here:\n");
$line = <STDIN>;

while ($line ne "") 
{
  if ($line =~ /\bthe\b/) {
    $thecount += 1;
  }
  $line = <STDIN>;
}

print ("Number of lines containing 'the': $thecount\n");

Output

Enter the input here:
Now is the time
for all good men
to come to the aid
of the party.
^D
Number of lines containing 'the': 3



ولتجاهل الرمز الخاص كال $, |, [, ), \, / فاذا اردت مطابقة اي من تلك الرموز استعمل backslash

\|              # Vertical bar 
\[              # An open square bracket
\)              # A closing parenthesis
\*              # An asterisk
\^              # A carat symbol
\/              # A slash
\\              # A backslash

بعض الامثله:
[01] اما 0 او 1
\/0 القسمة بواسطة الصفر "/0"
\/ 0 القسمة بالصفر مع فراغ "/ 0"
\/\s0 القسمة بالصفر مع whitespace حيث يمكن ان space او tab ... الخ .
\/ *0 القسمة بالصفر مع احتمال ان تكون هناك بعض الفراغات كال "/0" او "/ 0" ...الخ .
\/\s*0 القسمة بالصفر مع احتمال ان تكون هناك بعض whitespace
\/\s*0\.0* كاسابق لكن مع النقطة العشرية كا "/0." و "/0.0" و "/0.00" ....الخ "/ 0." و "/ 0.0" .....الخ.

تستطيع تحديد المدى للحرف وكم عدد الاحرف التي تريد حدوثها باستعمال رمز { }

امثلة :
/de{1,3}f/ المطابقة كحد ادني حرف 1 وحد الاقصى 3 حروف للحرف e، و يمكن ان تطابق def, deef, deeef ولايمكن ان تطابق df,deeeef .
/de{3}f/ تحديد حد الحرف e ثلاثة تماماً ، يطابق deeef
/de{3,}f/ لتحديد العدد الادني للحرف e على الاقل 3 .
/de{0,3}f/ لتحديد العدد الاقصى للحرف e ، ليس اكثر من ثلاثة e.
/[a-z]{1,3}/ حرف او 2او 3 من الحروف الصغيرة
/.{3}/ اي ثلاثة حروف .

 
#!/usr/bin/perl
print ("Enter a number:\n");
$number = <STDIN>;
chop ($number);
if ($number =~ /^-?\d+$|^0[xX][\da-fA-F]+$/) {
  print ("$number is a legal integer.\n");
} 
else {
  print ("$number is not a legal integer.\n");
}

Output

Enter a number:
0x3ff1
0x3ff1 is a legal integer.



نلاحظ انها تقوم بالفحص اذا كان الرقم المدخل صحيح في السطر،فالتعبير المنتظم مجزاء الى جزئين :

^-?\d+$ للقيم العشرية
^0[xX][\da-fA-F]+$ للقيم السادس عشر
^ للفحص من بداية السطر .
-? واحد او لاشئ ، للتاكد من وجود الأشارة السالبة للعدد -
0 ليقودنا الى 0
[xX] اما x او X
[\da-fA-F]+اما واحد او اكثر من رقم او حرف من a الى f او A الى F .
$ لإغلاق النمط والتأكد من التطابق الصحيح للعدد .


استعمال النمط مرة اخرى

البيرل تدعم التكرارات في النمط فمثلاً

/[\da-z]+[:;][\da-z]+[:;][\da-z]+/

فنلاحظ ان النمط يستعمل بتكرار ، هناك طريقة اسهل في البيرل للتضمين جزء من النمط في الذاكرة وعند الحاجة اليه يتم استداعاء الجزء ،فعندما نستعمل مع رموز علامات الحصر ( ... ) النمط او جزء النمط يخزن في الذاكرة

([\da-z]+)

يخزن هنا مفسر البيرل جزء النمط في الذاكرة ، وعند استدعى جزء النمط نستعمل فقط \n، حيث يمثل n الرقم المخزن في الذاكرة ، على سبيل المثال النمط المكتوب اعلى يمكن ان يكتب بالشكل التالي :

/([\da-z]+)[:;]\1[:;]\1/

ايضاً من الممكن تخزين[:;] في الذاكرة ليصبح النمط كالتالي

/([\da-z]+)([:;])\1\2\1/

التخزين في الذاكرة يتم من اليسار الى اليمين ، وذلك يعني ان 1 يمثل جزء النمط [\da-z]+ ، و 2 يمثل جزء النمط [:;] .

تلميح:
التخزين في الذاكرة لايهتم بالحرف الخاصة فمثلاً لو اردنا مطابقة التأريخ dd-mm-yy

/\d{2}([\W])\d{2}\1\d{2}/

يمكن ان يطابق
12-05-92
26.11.87
07 04 92
ولكن على اية حال 21-05.91 لايطابق .


المطابقة مع m//

في السابق استخدمنا محدد delimiter الانماط // فذلك يختصر من كتابة معامل المطابقة m// الى مطابقة النمط ونستطيع كتابة مطابقة النمط بدون او بإستخدام المعامل m ، كما يمكن استبدال اشكال المعامل وأستخدام محددات مختلفة مثل m<…> او m(…) او m{…} او m!…! او m"…"

المثال التالي يوضح ذلك عندما نرغب في مطابقة /u/jqpublic/perl/prog1

/\/u\/jqpublic\/perl\/prog1/

من الضرورة ان تجاهل الرمز / فمن السهل استخدام معامل m مع محدد مختلف مثل !

m!/u/jqpublic/perl/prog1!

متغيرات سلسة النمط

عندما يطابق سلسة من الانماط في الذاكرة فانها تخزن قيمة النمط في موقع كل جزء ،ويمكننا الوصول الى تلك القيمة بإستخدام المتغيرات $n ، حيث n هو مجموعة الانماط المخزنة

فعلى سبيل المثال لمطابقة الاعداد الحقيقية floating-point بدون استعمال الاسية في الترقيم

$string = "This string contains the number 25.11.";
$string =~ /-?(\d+)\.?(\d+)/;
$integerpart = $1;	
$decimalpart = $2;

هذا يعني ان 25 تخصص للمتغير الاول ، 11 تخصص للمتغير الثاني ، وتستطيع استعمال المتغير الخاص $& لإستراجاع كل المتغيرات (يخزن فيه المطابقة الصحيحة)

$string = "This string contains the number 25.11.";
$string =~ /-?(\d+)\.?(\d+)/;
$number = $&;

في هذا الحالة يخصص المتغير number بالقيمة 25.11 .

مثال اخر

$_ = 'http://www.perl.org/index.html'; 
if(m#^http://([^/]+)(.*)#) {
print "host = $1\n"; # host = www.perl.org
print "path = $2\n";# path = /index.html
}

الاسبقية في مؤثرات النمط

الاسبقية الوصف
() Pattern memory
+ * ? {} Number of occurrences
^ $ \b \B Pattern anchors
| Alternatives



خيارات مطابقة النمط

هناك عده خيارات للنمط لسيطرة على كيفية مطابقة النمط ، فكل الخيارات تأتي بعد النمط ويمكنك تحدد اكثر من خيار وكما تريد :

الخيار الوصف
g مطابقة العديد من المرات وكل الأنماط المحتملة Global match
i حالة غيرحساسة لحالة الحرف Case insensitive
m معالجة النص مع العديد من السطور ، ويسمح للـanchors لمطابقة قبل وبعد السطر الجديد Treat text as multiple lines
o تقدير النمط فقط مرة واحدة Compile once
s معالجة النص كسطر وحيد ، ويسمح للاسطرالجديدة للمطابقة Treat string as single line
x يسمح للـ whitespace في النمط Expanded regular expression
c الموقع المحتفظ في اخر مطابقة عند الفشل (هو فقط مع الخيار g )


الخيار g

فأذا كان النمط مع الخيار g سوف يحدد مجموعة مع كل المطابقات الصحيحة ، فعلى سبيل المثال اذا اردنا مطابقة الكلمة balata

@matches = "balata" =~ /.a/g;

الان سوف تخزن في مصفوفة مطابقات بشكل ("ba", "la", "ta") ، ففي البداية يخصص العنصرالاول بالـ ba في اول مطابقة صحيحة ثم يخصص العنصر الثاني بثاني مطابقة صحيحة ...الى انتهاء عملية مطابقة النمط .

#!/usr/bin/perl
while ("balata" =~ /.a/g) {
  $match = $&;
  print ("$match\n");
}

استعملنا التكرار لتخصيص المطابقة الصحيحة للمتغير وطباعتة ، ثم الانتقال للمطابقة الثاني ... الى الإنتهاء (المتغير الخاص $& يقوم بعمل نسخ للمطابقة الحالية ، ايضاً المتغير الخاص $` للمطابقات السابقة ، $' للمطابقات التالية ) .


Output

ba
la
ta



ولايجاد موقع المطابقة للنص عندما الخيار g يحدد نستخدم الدالة pos فهي تعيد بداية موقع المطابقة التالية (حيث يبداء البحث من بداية النص )

$offset = pos($string);

وعند استعمال الدالة بالطرف الايسار فذلك يعني انة سوف يبداء البحث من ذلك الموقع المحدد

pos($string) = $newoffset;


الخيار i يحدد حالة الحرف اما بحروف صغيرة او كبيرة مثل /de/i يطابق الكلمات de او dE او De او DE . على سبيل المثال رغبنا في وضع قائمة الاوامر يدخلها المستخدم مثل "send", "abort", "list", "edit"يضع المستخدم احدها لكن أسبقية كل امر على الاخر بحسب الترتيب :

chomp($answer = <>);
if    ("SEND"  =~ /^\Q$answer/i) { print "Action is send\n"  }
elsif ("STOP"  =~ /^\Q$answer/i) { print "Action is stop\n"  }
elsif ("ABORT" =~ /^\Q$answer/i) { print "Action is abort\n" }
elsif ("LIST"  =~ /^\Q$answer/i) { print "Action is list\n"  }
elsif ("EDIT"  =~ /^\Q$answer/i) { print "Action is edit\n"  }

الخيار m يخبر البيرل لمعالجة النص مع العديد من السطور ،فعندما الخيار يحدد مع الحرف الخاص ^ فهذا يعني انة سيبحث في بداية النص او في كل بداية سطر جديد

/^Th/m وهو مطابق This pattern matches\nThe first word on the second line

ومع الحرف الخاص $ يطابق في كل نهاية للسطر الجديد فمثلاً

/line.$/m يطابق This is the end of the first line.\nHere's another line.

الخيار o فهو يمكنك من اخبار البيرل بالتقدر النمط فقط مرة واحدة في وقت التجميع فعلى سبيلي المثال

#!/usr/bin/perl
$var = 1;
$line = ;
while ($var < 10) {
        $result = $line =~ /$var/o;
        $line = ;
        $var++;
}

فاولأ سوف تخصص القيمة 1 الى المتغير var ،ثم مفسر البيرل ينظر الى النمط ويستبدل المتغير بالقيمة أي يصبح النمط /1/ ، فالخيار oسوف يحتفظ بهذة القيمة وحتي وان تغير المتغير var يبقي في هذة الحالة /1/ ،فاذا كان الخيار o غير موجود فان النمط سوف يتغير الى /2/ .. /3/ .. /9/ ، ولاحظ ان قيمة المتغير result سوف يحوي القيمة 1 اذا كانت المطابقة صحيحة او true


الخيار s

وعند تحديد الخيار s فأن المعالجة على النص تسمح للاسطر الجديدة ، فعلى سبيل المثال الحرف الخاص للنمط dot لايطابق السطر الجديد "ضمن سطر فقط او وحيد" ، فأذا كان لديك اسطر جديدة في النص واردت dot من مطابقتهم فعليك تحدد الخيار s

$_ = "I saw Barney\ndown at the bowling alley\nwith Fred\nlast night.\n";
if (/Barney.*Fred/s) {
  print "That string mentions Fred after Barney!\n";
}

وبدون الخيار لان يطابق بسبب ان dot لايطابق السطر الجديد .


الخيار x يسمح بإظافة whitespace داخل النمط ليصبح اسهل للقراءة فمثلاً

/-?\d+\.?\d*/         # what is this doing?
/ -? \d+ \.? \d* /x   # a little better

# يمكن وضع التعليقات
/
      -?      # an optional minus sign
      \d+     # one or more digits before the decimal point
      \.?     # an optional decimal point
      \d*     # some optional digits after the decimal point
/x            # end of pattern


الإبدال مع s///

هي كالـ sed في اليونكس فمفسر البيرل يسمح بتبديل النص بنص اخر باستخدام معامل التبديل s/// فمثلاًُ نريد ابدال Barney بي Frd

#!/usr/bin/perl
$_ = "He's out bowling with Barney tonight.";
    s/Barney/Frd/;  # Replace Barney with Frd
print "$_\n";

وفاذا كانت المطابقة خاطئة لان يحدث شيء، وهنا بعض الابدلات الاخرى

$_ = "green scaly dinosaur";
s/(\w+) (\w+)/$2, $1/;# Now it's "scaly, green dinosaur"
s/^/huge, /;          # Now it's "huge, scaly, green dinosaur"

s/,.*een//;      # Empty replacement: Now it's "huge dinosaur"
s/green/red/;         # Failed match: still "huge dinosaur"
s/\w+$/($`!)$&/;      # Now it's "huge (huge !)dinosaur"
s/\s+(!\W+)/$1 /;     # Now it's "huge (huge!) dinosaur"

#يمكن تغير  s/// برمز اخر
S#huge#gigantic#;     # Now it's "gigantic (huge!) dinosaur"

في الامثلة السابقة لربما لاحظت ان s/// تقوم بإستبدال واحد فقط حتي اذا كان البقية مطابق ،فالخيار /g يعمل على إستبدال كل مطابق .

$_ = "home, sweet home! homepage";
s/home/cave/g;
print "$_\n";  # "cave, sweet cave! cavepage"

ولمنع التداخل

$_ = "home, sweet home! homepage";
s/\bhome\b/cave/g;
print "$_\n";  # "cave, sweet cave! homepage"

واذا اردت استبدال whitespace من بداية ونهاية السطر

s/^\s+//;  # Replace leading whitespace with nothing
s/\s+$//;  # Replace trailing whitespace with nothing

# او بخطوة واحدةلكن باقل سرعة
s/^\s+|\s+$//g;  # Strip leading, trailing whitespace

بنفس خيارات المطابقة الاخرى تستعمل مع الإبدال ، مع اضافة خيار اضافي e الذي يعالج النص البديل كتعبير ويقدر قبل الاستبدال

$string = "0abc1";
$string =~ s/[a-zA-Z]+/$& x 2/e;

المطابقة /[a-zA-Z]+/ تطابق abc وتخزن في $& ثم يقدر التعبير $& x 2 والناتج abcabc ، ثم تسبدل abc بالناتج abcabc ، هذا يعني ان القيمة الجديدة للمتغير string هي 0abcabc1


الترجمة مع tr///

هي طريقة اخرى لإستبدال حرف من مجموعة أحرف باستعمال معامل الترجمة tr/// او y/// وهو الاسرع للبحث عن حرف من مجموعة الاحرف

tr/string1/string2/
فاول حرف من string1 يستبدل بأول حرف من string2 وثاني حرف مع ثاني حرف ...وهكذا ، فعلى سبيل المثال :

$string = "abcdefgxxcba";
$string =~ tr/abc/def/;
$string =~ tr/[a-z]/[A-Z]/;
$string =~ tr/\t\n/ /; 
$string =~ tr/a-nA-Nm-zM-Z/m-zM-Za-nA-N/;استبدال النصف الاول مع الثاني  

اذا كان قائمة النصوص الايسر اطول من الايمن فسوف يكرر الحرف الاخير على سبيل المثال :

$string = "abcdefgh";
$string =~ tr/efgh/abc/; # abcdabcc 

فالغالب معامل الترجمة يستعمل للتحويل بين الاحرف الصغيرة والكبيرة ، فعند استعمال نفس الحرف في قائمة من الاحرف يستبدل باول حرف:

$string =~ tr/AAA/XYZ/; #replaces A with X
$vowel_count = $string =~ tr/ae//;# لاعادة عدد الاحرف المستبدلة 

خيارات الترجمة :

توفر الترجمة القياسية ثلاث خيارات هي (c, d, s) التي تعدل من طبيعة الترجمة

الخيار c او compliment modifier فهو يعكس المعني الذي يتضمن كل الاحرف ماعدا القائمة المراد البحث عنها ، على سبيل المثال للإستبدال كل الارقام او الرموز او whitespace ماعدا السطر الجديد بعلامة ؟

$string =~ tr/a-zA-Z\n/?/c;

الخيار d او delete modifier يزيل اي حرف محدد في قائمة البحث ، فاذا كان نص البحث اطول من نص الاستبدال ، تستبدل بدون اي امتداد .

$string =~ tr/efgh/abc/d; # abcdab 

الخيار s او squash modifier يزيل الحرف المكرر مرتين او اكثر في الناتج واخرجة بحرف واحد فقط،علىسبيل المثال

$text =~ tr/\t\n/ /s;
# translate any whitespace to literal space and remove resulting duplicates 

يمكن استعمال الثلاثة الخيارات كمجموعة مع بعضهم البعض ، فعلى سبيل المثال لإستبدال اي حرف( ماعدا الارقام ) بافراغ مع إزلة الفراغات المتكررة .

$string =~ tr/0-9/ /cs; 

الدالة split

لديها ثلاثة وسطاء ومع الوسيط الاول تبحث عن النمط المطابق ويمكن ان يتضمن هذا الوسيط اما بعلامات اقتباس فردية او مضاعفة ، وطبيعياً فان التعبيرات المنتظم في هذة الدالة ليس واضح جداً كالاستعمالات العادية للنمط

الشكل العادي للدالة split

$text = " ,two pints of , milk and a pot of yoghurt\n";
# تقسيم النص الى قطعتين ,
@values = split (',',$text);

فنمط البحث فقط سيطابق رمز comma , ، ويمكن ان يستبدل التعبير بحذف الـــ whitespace من القيم الراجعه للعنصر المصفوفة باستخدام

@values = split('\s*,\s*',$text); # مع علامة الاقتباس
@values = split /\s*,\s*/,$text; # بدون علامات الحصر

ولاحظ في هذا المثال لايعالج whitespace في بداية ونهاية النص ،كما هي مع المطابقة والابدال فادالة split تربط الى المتغير الخاص $_ اذا لم يتضمن نص للبحث علية ، ويمكن كتابة التعبير بوسيط واحد

@csv = split /,/;   # split $_ on commas

فاذا كانت الدالة بدون اي وسيط ستاخذ المتغير الخاص $_ مع whitespace ، وباكثر دقة تاخذ النمط المسافة ' ' (التي هي خاصة فقط للدالة split ) التي لن تعيد قيمة فارغة في البداية، وهي مكافئة للـ \s+ و غير ذلك فلن تعيد قيمة فارغة اذا كانت النص يبداء مع whitespace :

# split $_ on whitespace, explicitly (leading whitespace returns an empty
# value)
@words = split /\s+/,$_;
# split $_ on whitespace, implicitly (leading whitespace does not return an
# empty value)
@words = split;
# The same as 'split' on its own
@words = split ' ';

اذا كانت الرغبة لعمل split على بستعمال الفرغات ، نجهز مع regexp حرفي بدلاًُ من ذلك :

# split on individual spaces
@words = split / /;

فالدالة split لاتستعمل المعاملات =~ او !~ فهي وظيفة سهلة مضافة باستعمال مطابقة regexp لكن الدالة split تقراء افضل بكثير من الكلمة المحجوزة join .


الدوال map & grep

بسبب تعلق الدالة grep بالنمط ، فالدلتان تحولن المصفوفة الى مصفوفة اخرى ام بنتقال القيم او بمؤافقة شرط معين وذلك للتسهيل الكود ومعرفة تركيب استعمال هذة الدوال ، فبدلاً من استعمال التكرات foreach وwhile لتؤليد مصفوفة جديدة نستطيع ان نفعل ذلك بستعمال الدوال وبشكل افضل .

والصيغة تاخذ شكلين متكافين :

map EXPRESSION, LIST         grep EXPRESSION, LIST
map BLOCK LIST               grep BLOCK LIST

فغرض EXPRESSION او BLOCK هو لتنفيذ كل عناصر المصفوفة ، والناتج يعاد الى المصفوفة الجديدة، فالـ map هي متعلقة بفهموم التكرار foreach ، اما grep هي للعائدة محتوى القائمة الجزئية للقائمة الاصلية و expression هذة الدالة يقدر اما بالقيمة true او false وهي متعلقة بفهوم التكرار while

الدالة map تستعمل للانتقال كل القيم في القائمة الى قائمة اخر، هنا مثال لمشاهد كيف تعمل بفرض اننا ناخذ مصفوفة اعداد صحيحة ونريد اعادة هذة القيم الى حروف باستعمال الدالة الخاصة chr

my @numbers = (80, 101, 114, 108);
my @characters;
foreach (@numbers) {
push @characters, chr $_;
}
print @characters;

وبنفس العمل يمكن استعمال الدالة map

my @characters = map (chr $_, @numbers);

او بستعمال صيغة BLOCK

my @characters = map {chr $_} @numbers;

فهذا الشئ مفيد بتقليص عدد الاسطر الى سطر واحد فباستعمال الدالة map سوف تعيد الناتج كمصفوفة ويمكن ان نرجع الناتج الى البرنامج الرئيسي بكفاءة :

#!/usr/bin/perl
# callsub.pl
use warnings;
use strict;
sub do_list {
my ($subref, @in) = @_;
return map { &$subref ($_) } @in;
}
sub add_one {
return $_[0] + 1;
}
$, = ",";
print do_list (\&add_one, 1, 2, 3); # prints 2, 3, 4
perldoc -f map

grep

أسم الدالة grep ماخوذة من الامر grep في اليونكس الذي عمله البحث في الملفات النصية ويعيد السطور المطابقة للنمط .ومفهومها مشابة في البيرل حيث يعيد القائمة المطابقة من القائمة الاصلية بمؤافقة شرط التطابق .

my @numerics = ();
while (<>) {
push @numerics, $_ if /^\d/;
}
print "@numerics\n"
@numerics = grep {/^\d/} <>

مجموعة تعبيرات منتظمة مفيدة

قابليت التعبيرات المنتظمة للتطبيق المتنوع في الحواسيب من اهم الاسباب الباعثة للنظريات الاحسابية formal language theory و automata theory وجزء رئيسي في االانظمة والبرمجيات وفي الاخير يوجد هنا بعض التعبيرات المنتظمة المفيدة اذا ارادت التعرف والاطلاع اكثر كتاب Mastering Regular Expressions O'Reilly و Perl Cookbook, 2nd Edition:

Check for valid currency value 
^([0-9]+|[0-9]{1,3}(,[0-9]{3})*)(\.[0-9]{1,2})?$

Check for valid email address
^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*$

Swap first two words 
s/(\S+)(\s+)(\S+)/$3$2$1/

Keyword = Value 
m/^(\w+)\s*=\s*(.*?)\s*$/             # keyword is $1, value is $2

Line of at least 80 characters 
m/.{80,}/
او
length( ) >= 80        # ok, not a regex

MM/DD/YY HH:MM:SS 
m|(\d+)/(\d+)/(\d+) (\d+):(\d+):(\d+)|

Changing directories 
s(/usr/bin)(/usr/local/bin)g

Expanding %7E (hex) escapes 
s/%([0-9A-Fa-f][0-9A-Fa-f])/chr(hex($1))/ge

Deleting C comments (imperfectly) 
s{
    /*                    # Match the opening delimiter
    .*?                   # Match a minimal number of characters
    */                    # Match the closing delimiter
}{  }gsx;

Removing leading and trailing whitespace 
s/^\s+//;
s/\s+$//;

Turning \ followed by n into a real newline 
s/\\n/\n/g;

Removing package portion of fully qualified symbols 
s/^.*:://

Dotted quads (most IP addresses) 
# XXX: fails on legal IPs 127.1 and 2130706433.
m{
        ^  ( \d | [01]?\d\d | 2[0-4]\d | 25[0-5] )
       \.  ( \d | [01]?\d\d | 2[0-4]\d | 25[0-5] )
       \.  ( \d | [01]?\d\d | 2[0-4]\d | 25[0-5] )
       \.  ( \d | [01]?\d\d | 2[0-4]\d | 25[0-5] )
        $
    }x

Removing leading path from filename 
s{^.*/}{  }

Extracting columns setting from TERMCAP 
$cols = ( ($ENV{TERMCAP} || " ") =~ m/:co#(\d+):/ ) ? $1 : 80;

Removing directory components from program name and arguments 
($name = " $0 @ARGV") =~ s{ /\S+/}{ }g;

Checking your operating system 
die "This isn't Linux" unless $^O =~ m/linux/i;

Joining continuation lines in multiline string 
s/\n\s+/ /g

Extracting all numbers from a string 
@nums = m/(\d+\.?\d*|\.\d+)/g;

Finding all-caps words 
@capwords = m/(\b\p{ Upper-case Letter }+\b)/g;

Finding all-lowercase words 
@lowords = m/(\b\p{ Lower-case Letter }+\b)/g;

Finding initial-caps word 
@icwords = m{
    ( \b
        [\p{ Upper-case Letter }\p{ Title-case Letter }]
        \p{  Lower-case Letter } *
    \b )
}gx;

Finding links in simple HTML 
@links = m/]+?HREF\s*=\s*["']?([^'" >]+?)['"]?\s*>/ig;

Finding middle initial in $_ 
$initial = /^\S+\s+(\S)\S*\s+\S/ ? $1 : "";

Changing double verticle prime pairs to curly quotes 
s/"([^"]*)"/``$1''/g                        # old way

# next is unicode only
s/"([^"]*)"/\x{201C}\x{201C}$1\x{201D}\x{201D}/g

Extracting sentences (double spaces required between each) 
{ local $/ = "";
    while (<>) {
        s/\n/ /g;
        s/ {3,}/  /g;
        push @sentences, m/(\S.*?[!?.])(?= {2}|\Z)/g;
    }
}

YYYY-MM-DD 
m/\b(\d{4})-(\d\d)-(\d\d)\b/           # YYYY in $1, MM in $2, DD in $3

North American telephone numbers 
m/ ^
      (?:
       1 \s (?: \d\d\d \s)?            # 1, or 1 and area code
       |                               # ... or ...
       \(\d\d\d\) \s                   # area code with parens
       |                               # ... or ...
       (?: \+\d\d?\d? \s)?             # optional +country code
       \d\d\d ([\s\-])                 # and area code
      )
      \d\d\d (\s|\1)                   # prefix (and area code separator)
      \d\d\d\d                         # exchange
      $
 /x

Exclamations 
m/\boh\s+my\s+gh?o(d(dess(es)?|s?)|odness|sh)\b/i

Extracting lines regardless of line terminator 
push(@lines, $1) while $input =~ s{
    ^                                # gobble from front

    (     
          .                         # begin $1: any single char (/s)
          ?*                         # but minimally matching even none
    )                        

    (?:                           # make capturing if saving terminators
          \x0D \x0A                # CRLF        
      |   \x0A                 # LF
      |   \x0D                # CR
      |   \x0C                # FF
# (see http://www.unicode.org/reports/tr13/tr13-9.html)
      |   \x{2028}                # Unicode LS
      |   \x{2029}                # Unicode PS
    )
}{  }sx;                        # consumes $input
Or use split:

@lines = split m{
  (?:                           # make capturing if saving terminators
        \x0D \x0A                # CRLF        
    |   \x0A                 # LF
    |   \x0D                # CR
    |   \x0C                # FF
  # (see http://www.unicode.org/reports/tr13/tr13-9.html)
    |   \x{2028}                # Unicode LS
    |   \x{2029}                # Unicode PS
  )
}x, $input;